//
//  NSRunLoop.swift
//  Documentation
//
//  Created by Toj on 2/7/23.
//

import CoreFoundation

// MARK: - 运行模式
extension RunLoop.Mode {
    
    // 默认
    public static let `default`: RunLoop.Mode

    // 通用模式
    @available(iOS 2.0, *)
    public static let common: RunLoop.Mode
}

open class RunLoop : NSObject {

    // 当前运行循环
    open class var current: RunLoop { get }

    // 主运行循环
    @available(iOS 2.0, *)
    open class var main: RunLoop { get }

    // 当前模式
    open var currentMode: RunLoop.Mode? { get }

    // 桥接CFRunLoop
    open func getCFRunLoop() -> CFRunLoop

    // 把Timer添加到当前运行循环内
    open func add(_ timer: Timer, forMode mode: RunLoop.Mode)

    // 把Port添加到当前运行循环内
    open func add(_ aPort: Port, forMode mode: RunLoop.Mode)

    // 把Timer添加到当前运行循环内
    open func remove(_ aPort: Port, forMode mode: RunLoop.Mode)

    
    open func limitDate(forMode mode: RunLoop.Mode) -> Date?

    open func acceptInput(forMode mode: RunLoop.Mode, before limitDate: Date)
}

@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
extension RunLoop : Scheduler {

    /// The scheduler time type used by the run loop.
    public struct SchedulerTimeType : Strideable, Codable, Hashable {

        /// The date represented by this type.
        public var date: Date

        /// Initializes a run loop scheduler time with the given date.
        ///
        /// - Parameter date: The date to represent.
        public init(_ date: Date)

        /// Returns the distance to another run loop scheduler time.
        ///
        /// - Parameter other: Another dispatch queue time.
        /// - Returns: The time interval between this time and the provided time.
        public func distance(to other: RunLoop.SchedulerTimeType) -> RunLoop.SchedulerTimeType.Stride

        /// Returns a run loop scheduler time calculated by advancing this instance’s time by the given interval.
        ///
        /// - Parameter n: A time interval to advance.
        /// - Returns: A dispatch queue time advanced by the given interval from this instance’s time.
        public func advanced(by n: RunLoop.SchedulerTimeType.Stride) -> RunLoop.SchedulerTimeType

        /// The interval by which run loop times advance.
        public struct Stride : ExpressibleByFloatLiteral, Comparable, SignedNumeric, Codable, SchedulerTimeIntervalConvertible {

            /// A type that represents a floating-point literal.
            ///
            /// Valid types for `FloatLiteralType` are `Float`, `Double`, and `Float80`
            /// where available.
            public typealias FloatLiteralType = TimeInterval

            /// A type that represents an integer literal.
            ///
            /// The standard library integer and floating-point types are all valid types
            /// for `IntegerLiteralType`.
            public typealias IntegerLiteralType = TimeInterval

            /// A type that can represent the absolute value of any possible value of the
            /// conforming type.
            public typealias Magnitude = TimeInterval

            /// The value of this time interval in seconds.
            public var magnitude: TimeInterval

            /// The value of this time interval in seconds.
            public var timeInterval: TimeInterval { get }

            /// Creates an instance initialized to the specified integer value.
            ///
            /// Do not call this initializer directly. Instead, initialize a variable or
            /// constant using an integer literal. For example:
            ///
            ///     let x = 23
            ///
            /// In this example, the assignment to the `x` constant calls this integer
            /// literal initializer behind the scenes.
            ///
            /// - Parameter value: The value to create.
            public init(integerLiteral value: TimeInterval)

            /// Creates an instance initialized to the specified floating-point value.
            ///
            /// Do not call this initializer directly. Instead, initialize a variable or
            /// constant using a floating-point literal. For example:
            ///
            ///     let x = 21.5
            ///
            /// In this example, the assignment to the `x` constant calls this
            /// floating-point literal initializer behind the scenes.
            ///
            /// - Parameter value: The value to create.
            public init(floatLiteral value: TimeInterval)

            public init(_ timeInterval: TimeInterval)

            /// Creates a new instance from the given integer, if it can be represented
            /// exactly.
            ///
            /// If the value passed as `source` is not representable exactly, the result
            /// is `nil`. In the following example, the constant `x` is successfully
            /// created from a value of `100`, while the attempt to initialize the
            /// constant `y` from `1_000` fails because the `Int8` type can represent
            /// `127` at maximum:
            ///
            ///     let x = Int8(exactly: 100)
            ///     // x == Optional(100)
            ///     let y = Int8(exactly: 1_000)
            ///     // y == nil
            ///
            /// - Parameter source: A value to convert to this type.
            public init?<T>(exactly source: T) where T : BinaryInteger

            /// Returns a Boolean value indicating whether the value of the first
            /// argument is less than that of the second argument.
            ///
            /// This function is the only requirement of the `Comparable` protocol. The
            /// remainder of the relational operator functions are implemented by the
            /// standard library for any type that conforms to `Comparable`.
            ///
            /// - Parameters:
            ///   - lhs: A value to compare.
            ///   - rhs: Another value to compare.
            public static func < (lhs: RunLoop.SchedulerTimeType.Stride, rhs: RunLoop.SchedulerTimeType.Stride) -> Bool

            /// Multiplies two values and produces their product.
            ///
            /// The multiplication operator (`*`) calculates the product of its two
            /// arguments. For example:
            ///
            ///     2 * 3                   // 6
            ///     100 * 21                // 2100
            ///     -10 * 15                // -150
            ///     3.5 * 2.25              // 7.875
            ///
            /// You cannot use `*` with arguments of different types. To multiply values
            /// of different types, convert one of the values to the other value's type.
            ///
            ///     let x: Int8 = 21
            ///     let y: Int = 1000000
            ///     Int(x) * y              // 21000000
            ///
            /// - Parameters:
            ///   - lhs: The first value to multiply.
            ///   - rhs: The second value to multiply.
            public static func * (lhs: RunLoop.SchedulerTimeType.Stride, rhs: RunLoop.SchedulerTimeType.Stride) -> RunLoop.SchedulerTimeType.Stride

            /// Adds two values and produces their sum.
            ///
            /// The addition operator (`+`) calculates the sum of its two arguments. For
            /// example:
            ///
            ///     1 + 2                   // 3
            ///     -10 + 15                // 5
            ///     -15 + -5                // -20
            ///     21.5 + 3.25             // 24.75
            ///
            /// You cannot use `+` with arguments of different types. To add values of
            /// different types, convert one of the values to the other value's type.
            ///
            ///     let x: Int8 = 21
            ///     let y: Int = 1000000
            ///     Int(x) + y              // 1000021
            ///
            /// - Parameters:
            ///   - lhs: The first value to add.
            ///   - rhs: The second value to add.
            public static func + (lhs: RunLoop.SchedulerTimeType.Stride, rhs: RunLoop.SchedulerTimeType.Stride) -> RunLoop.SchedulerTimeType.Stride

            /// Subtracts one value from another and produces their difference.
            ///
            /// The subtraction operator (`-`) calculates the difference of its two
            /// arguments. For example:
            ///
            ///     8 - 3                   // 5
            ///     -10 - 5                 // -15
            ///     100 - -5                // 105
            ///     10.5 - 100.0            // -89.5
            ///
            /// You cannot use `-` with arguments of different types. To subtract values
            /// of different types, convert one of the values to the other value's type.
            ///
            ///     let x: UInt8 = 21
            ///     let y: UInt = 1000000
            ///     y - UInt(x)             // 999979
            ///
            /// - Parameters:
            ///   - lhs: A numeric value.
            ///   - rhs: The value to subtract from `lhs`.
            public static func - (lhs: RunLoop.SchedulerTimeType.Stride, rhs: RunLoop.SchedulerTimeType.Stride) -> RunLoop.SchedulerTimeType.Stride

            /// Multiplies two values and stores the result in the left-hand-side
            /// variable.
            ///
            /// - Parameters:
            ///   - lhs: The first value to multiply.
            ///   - rhs: The second value to multiply.
            public static func *= (lhs: inout RunLoop.SchedulerTimeType.Stride, rhs: RunLoop.SchedulerTimeType.Stride)

            /// Adds two values and stores the result in the left-hand-side variable.
            ///
            /// - Parameters:
            ///   - lhs: The first value to add.
            ///   - rhs: The second value to add.
            public static func += (lhs: inout RunLoop.SchedulerTimeType.Stride, rhs: RunLoop.SchedulerTimeType.Stride)

            /// Subtracts the second value from the first and stores the difference in the
            /// left-hand-side variable.
            ///
            /// - Parameters:
            ///   - lhs: A numeric value.
            ///   - rhs: The value to subtract from `lhs`.
            public static func -= (lhs: inout RunLoop.SchedulerTimeType.Stride, rhs: RunLoop.SchedulerTimeType.Stride)

            /// Converts the specified number of seconds into an instance of this scheduler time type.
            public static func seconds(_ s: Int) -> RunLoop.SchedulerTimeType.Stride

            /// Converts the specified number of seconds, as a floating-point value, into an instance of this scheduler time type.
            public static func seconds(_ s: Double) -> RunLoop.SchedulerTimeType.Stride

            /// Converts the specified number of milliseconds into an instance of this scheduler time type.
            public static func milliseconds(_ ms: Int) -> RunLoop.SchedulerTimeType.Stride

            /// Converts the specified number of microseconds into an instance of this scheduler time type.
            public static func microseconds(_ us: Int) -> RunLoop.SchedulerTimeType.Stride

            /// Converts the specified number of nanoseconds into an instance of this scheduler time type.
            public static func nanoseconds(_ ns: Int) -> RunLoop.SchedulerTimeType.Stride

            /// Returns a Boolean value indicating whether two values are equal.
            ///
            /// Equality is the inverse of inequality. For any values `a` and `b`,
            /// `a == b` implies that `a != b` is `false`.
            ///
            /// - Parameters:
            ///   - lhs: A value to compare.
            ///   - rhs: Another value to compare.
            public static func == (a: RunLoop.SchedulerTimeType.Stride, b: RunLoop.SchedulerTimeType.Stride) -> Bool

            /// Encodes this value into the given encoder.
            ///
            /// If the value fails to encode anything, `encoder` will encode an empty
            /// keyed container in its place.
            ///
            /// This function throws an error if any values are invalid for the given
            /// encoder's format.
            ///
            /// - Parameter encoder: The encoder to write data to.
            public func encode(to encoder: Encoder) throws

            /// Creates a new instance by decoding from the given decoder.
            ///
            /// This initializer throws an error if reading from the decoder fails, or
            /// if the data read is corrupted or otherwise invalid.
            ///
            /// - Parameter decoder: The decoder to read data from.
            public init(from decoder: Decoder) throws
        }

        /// Hashes the essential components of this value by feeding them into the
        /// given hasher.
        ///
        /// Implement this method to conform to the `Hashable` protocol. The
        /// components used for hashing must be the same as the components compared
        /// in your type's `==` operator implementation. Call `hasher.combine(_:)`
        /// with each of these components.
        ///
        /// - Important: Never call `finalize()` on `hasher`. Doing so may become a
        ///   compile-time error in the future.
        ///
        /// - Parameter hasher: The hasher to use when combining the components
        ///   of this instance.
        public func hash(into hasher: inout Hasher)

        /// Encodes this value into the given encoder.
        ///
        /// If the value fails to encode anything, `encoder` will encode an empty
        /// keyed container in its place.
        ///
        /// This function throws an error if any values are invalid for the given
        /// encoder's format.
        ///
        /// - Parameter encoder: The encoder to write data to.
        public func encode(to encoder: Encoder) throws

        /// The hash value.
        ///
        /// Hash values are not guaranteed to be equal across different executions of
        /// your program. Do not save hash values to use during a future execution.
        ///
        /// - Important: `hashValue` is deprecated as a `Hashable` requirement. To
        ///   conform to `Hashable`, implement the `hash(into:)` requirement instead.
        public var hashValue: Int { get }

        /// Creates a new instance by decoding from the given decoder.
        ///
        /// This initializer throws an error if reading from the decoder fails, or
        /// if the data read is corrupted or otherwise invalid.
        ///
        /// - Parameter decoder: The decoder to read data from.
        public init(from decoder: Decoder) throws
    }

    /// Options that affect the operation of the run loop scheduler.
    public struct SchedulerOptions {
    }

    /// Performs the action at the next possible opportunity.
    public func schedule(options: RunLoop.SchedulerOptions?, _ action: @escaping () -> Void)

    /// Performs the action at some time after the specified date.
    public func schedule(after date: RunLoop.SchedulerTimeType, tolerance: RunLoop.SchedulerTimeType.Stride, options: RunLoop.SchedulerOptions?, _ action: @escaping () -> Void)

    /// Performs the action at some time after the specified date, at the specified frequency, optionally taking into account tolerance if possible.
    public func schedule(after date: RunLoop.SchedulerTimeType, interval: RunLoop.SchedulerTimeType.Stride, tolerance: RunLoop.SchedulerTimeType.Stride, options: RunLoop.SchedulerOptions?, _ action: @escaping () -> Void) -> Cancellable

    /// This scheduler’s definition of the current moment in time.
    public var now: RunLoop.SchedulerTimeType { get }

    /// The minimum tolerance allowed by the scheduler.
    public var minimumTolerance: RunLoop.SchedulerTimeType.Stride { get }
}

extension RunLoop {

    
    open func run()

    open func run(until limitDate: Date)

    open func run(mode: RunLoop.Mode, before limitDate: Date) -> Bool

    
    /// Schedules the execution of a block on the target run loop in given modes.
    /// - parameter: modes   An array of input modes for which the block may be executed.
    /// - parameter: block   The block to execute
    @available(iOS 10.0, *)
    open func perform(inModes modes: [RunLoop.Mode], block: @escaping () -> Void)

    
    /// Schedules the execution of a block on the target run loop.
    /// - parameter: block   The block to execute
    @available(iOS 10.0, *)
    open func perform(_ block: @escaping () -> Void)
}


/****************     Delayed perform     ******************/
extension NSObject {

    
    open func perform(_ aSelector: Selector, with anArgument: Any?, afterDelay delay: TimeInterval, inModes modes: [RunLoop.Mode])

    open func perform(_ aSelector: Selector, with anArgument: Any?, afterDelay delay: TimeInterval)

    open class func cancelPreviousPerformRequests(withTarget aTarget: Any, selector aSelector: Selector, object anArgument: Any?)

    open class func cancelPreviousPerformRequests(withTarget aTarget: Any)
}

extension RunLoop {

    
    open func perform(_ aSelector: Selector, target: Any, argument arg: Any?, order: Int, modes: [RunLoop.Mode])

    open func cancelPerform(_ aSelector: Selector, target: Any, argument arg: Any?)

    open func cancelPerformSelectors(withTarget target: Any)
}

